package top.v5it.japi.plus.data.jpa.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import java.util.List;

/**
 * 自定义{@link JpaRepository}的实现新增addBatch、updateBatch、deleteBatch方法
 *
 * @author zhanpu
 * @date 2021/3/19
 */
@NoRepositoryBean
public interface JapiJpaRepository<T, ID> extends JpaRepository<T, ID> {

    /**
     * 批量新增，按传入参数batchSize条刷新一次
     *
     * @param entities  实体对象
     * @param <S>       实体类型
     * @param batchSize 批次刷新数量
     * @return 实体对象
     */
    <S extends T> List<S> saveBatch(Iterable<S> entities, int batchSize);

    /**
     * 批量更新，按传入参数batchSize条刷新一次
     *
     * @param entities  实体对象
     * @param <S>       实体类型
     * @param batchSize 批次刷新数量
     * @return 实体对象
     */
    <S extends T> List<S> updateBatch(Iterable<S> entities, int batchSize);

    /**
     * 批量删除，按传入参数batchSize条刷新一次
     *
     * @param entities  实体对象
     * @param <T>       实体类型
     * @param batchSize 批次刷新数量
     */
    <T> void deleteBatch(Iterable<T> entities, int batchSize);

    /**
     * 动态更新对象，采用拼接hql语句，并绑定待更新字段，按whereProperty条件更新
     *
     * @param entity        实体对象
     * @param whereProperty 条件字段
     * @param <S>           实体类型
     * @return 实体对象
     */
    <S extends T> S dynamicUpdate(S entity, String... whereProperty);

    /**
     * 批量动态更新，按传入参数batchSize条提交一次，其内部调用{@link #dynamicUpdate}
     *
     * @param entities      实体对象
     * @param <S>           实体类型
     * @param batchSize     批次刷新数量
     * @param whereProperty 条件字段
     * @return 实体对象
     */
    <S extends T> List<S> dynamicUpdateBatch(Iterable<S> entities, int batchSize, String... whereProperty);

    /**
     * 保存或更新：
     * <p>id不存在时，执行新增</p>
     * <p>
     * id存在时，执行动态更新，需要实体对象开启{@link org.hibernate.annotations.DynamicUpdate}注解：
     * 1、先根据id查询对象，无需开发者手动查询；2、执行动态更新
     * </p>
     *
     * @param entity 实体对象
     * @param <S>    实体类型
     * @return 实体对象
     */
    <S extends T> S saveOrDynamicUpdate(S entity);

    /**
     * 新增或更新实体
     *
     * @param entity     实体对象
     * @param isOverride 是否更新原有数据，主要考虑在复合主键场景，当在不知情况下调用本方法，其本意是想新增实体，存在则新增失败或异常，结果可能导致数据库中已存在数据被覆盖重写
     * @param <S>实体类型
     * @return 实体对象
     */
    <S extends T> S save(S entity, boolean isOverride);
}
